<template>
  <div class="ui-element-warp">
    <input
      type="text"
      v-bind="$attrs"
      :value="value"
      class="ui-element-input"
      :class="{
        'ui-valid-fail':valid.status==='fail',
        'ui-valid-success':valid.status==='success',
      }"
      @blur="validate"
      @input="$emit('input', $event.target.value)"
    >
    <div v-if="valid.status==='fail'" class="ui-error-status">{{ valid.errorMessage }}</div>
  </div>
</template>

<script>
export default {
  name: 'UiInput',
  inheritAttrs: false,
  model: {
    prop: 'value',
    event: 'input'
  },
  props: {
    rules: {
      type: Array,
      default() {
        return []
      }
    },
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      valid: {
        status: 'init',
        errorMessage: ''
      }
    }
  },
  methods: {
    validate() {
      if (this.rules.length === 0) {
        return new Promise((resolve) => {
          resolve()
        })
      }
      this.execute(this.value, this.rules)
        .then(() => {
          this.valid = {
            status: 'success',
            errorMessage: ''
          }
        }).catch((error) => {
          this.valid = {
            status: 'fail',
            errorMessage: error.message
          }
        })
    },
    execute(value, rules) {
      return new Promise((resolve, reject) => {
        const len = rules.length
        let i = 0
        const arr = []
        function valid(val, rule) {
          rule.validator(val, rules, next)
        }
        function next(err) {
          if (arr.indexOf(i) !== -1) {
            return
          }
          arr.push(i)
          if (err) {
            reject({
              index: i,
              message: err.message
            })
          } else {
            if ((i + 1) < len) {
              i++
              valid(value, rules[i])
            } else {
              resolve()
            }
          }
        }
        if (len > 0) {
          valid(value, rules[i])
        } else {
          resolve()
        }
      })
    },
    validator() {
      if (this.rules.length === 0) {
        return new Promise((resolve) => {
          resolve()
        })
      } else {
        return this.execute(this.value, this.rules)
      }
    },
    resetField() {
      this.valid = {
        status: 'init',
        errorMessage: ''
      }
    }
  }
}
</script>

<style lang="less" scoped>
  .ui-element-warp{
    display: inline-block;
    width: 100%;
  }
  .ui-element-input{
    display: block;
    width: 100%;
    height: 36px;
    padding: 8px 10px;
    border-radius: 4px;
    font-size: 14px;
    color: #333333;
    outline: none;
    border: 1px solid #c9c9c9;
    box-sizing: border-box;
  }
  .ui-element-input:focus{
    border: 1px solid #2d8cf0;
  }
  .ui-element-input.ui-valid-success{
    border: 1px solid #039c59;
  }
  .ui-element-input.ui-valid-fail{
    border: 1px solid #ed4014;
  }
  .ui-error-status{
    line-height: 20px;
    font-size: 12px;
    height: 20px;
    color: #e64b15;
    padding: 0 10px;
    position: absolute;
    top: 100%;
    left: 0;
  }
</style>
